#include <Types.h>
#include <pci.h>

#define PCI_SERVICE	0x49435024

addr_t *pci_addr;

int32 find_pci_device(uint16 devid, uint16 vendid, uint32 index){
	uint16 busnr = 0, dfnr = 0, code = 0;
	asm("movb $0xb1, %ah");
	asm("movb $0x2, %al");
	asm("movw %0, %%cx"::"m" (devid));
	asm("movw %0, %%dx"::"m" (vendid));
	asm("movw %0, %%si"::"m" (index));
	asm("pushl %cs");
	asm("call 0xfb200");
	asm("movb %%ah, %0":"=m" (code));
	if(code) return -((int32)code);
	asm("movb %%bh, %0":"=m" (busnr));
	asm("movb %%bl, %0":"=m" (dfnr));
	return (busnr << 8) | dfnr;
}

int32 find_pci_class_code(uint32 ccode, uint32 index){
	uint16 dev = 0, code = 0;
	uint16 func = (PCI_FUNCTION_ID << 8) | FIND_PCI_CLASS_CODE;
	asm volatile("pushl $0x8; call *%5;":
		"=b" (dev), 
		"=a" (code):
		"a" (func), 
		"c" (ccode), 
		"S" (index), 
		"D" (pci_addr));
	code = (code & 0xFF00) >> 8;
	if(code) return -((int32)code);
	return dev;
}



/*Находит адрес BIOS32 Service Directory в памяти. Если удачно возвращает адрес, иначе NULL*/
struct bios32_sd_s * find_bios32(){
	struct bios32_sd_s *bios32_sd = (struct bios32_sd_s *) PCI_SCAN_START;
	while(bios32_sd <= (struct bios32_sd_s *) PCI_SCAN_STOP){
		if(bios32_sd->sig[0] == '_' &&
		   bios32_sd->sig[1] == '3' &&
		   bios32_sd->sig[2] == '2' &&
		   bios32_sd->sig[3] == '_'){
		   kprintf("Found!\n");
		   return bios32_sd;
		   }
		kprintf(".");
		++bios32_sd;
	}
	kprintf("Not found\n");
	return NULL;	
}

void * find_pcibios(struct bios32_sd_s *b32){
	uint32 retcode = 0, addr = 0, off = 0;
	asm volatile("pushl $0x8; call *%3;":
		"=a" (retcode), 
		"=b" (addr), 
		"=d" (off):
		"D" (b32->entery), 
		"a" (PCI_SERVICE), 
		"b" (0));
	retcode &= 0xFF;
	if(retcode > 0){
		kprintf("RETCODE: %X\n", retcode);
		return NULL;
	}
	kprintf("GOOD: a(%X), o(%X)\n", addr, off);
	pci_addr = (addr_t *) (addr + off);
	return (void *) (addr + off);
}

int	is_pcibios_exist(addr_t *pcibios_entery, struct pci_info_s *p_inf){
	uint16 func = (PCI_FUNCTION_ID << 8) | PCI_BIOS_PRESENT;
	uint32 pci_sig = 0;
	kprintf("BIOS ENTERY: %X\n", pcibios_entery);
	asm volatile("pushl $0x8; call *%5":
		"=a" (p_inf->hw_mech), 
		"=b" (p_inf->ver), 
		"=c" (p_inf->bus_nr), 
		"=d" (pci_sig):
		"a" (func), 
		"d" (pcibios_entery));
	kprintf("hw_mech: %X, ver: %X, busnr: %X, pcisig: %X\n", p_inf->hw_mech, p_inf->ver, p_inf->bus_nr, pci_sig);
	char *p = (char *)&pci_sig;
	kprintf("PCI SIG: %c %c %c %c\n", p[0], p[1], p[2], p[3]);
}

/*
			kprintf("PCI BIOS SDP ADDR: %X\n", bios32_sd->entery);
			kprintf("Revision: %i, length: %i\n", bios32_sd->conf[0], bios32_sd->conf[1]);
			
			asm("movl	$0x49435024, %eax; movl	$0, %ebx");
			asm("pushl %cs");
			asm("call 0xfd780");
			addr_t pci_base, pci_off, pci_addr;
			//asm("call %0"::"r" (bios32_sd->entery):"%ecx");
			asm("movl %%ebx, %0":"=m" (pci_base));
			asm("movl %%edx, %0":"=m" (pci_off));
			kprintf("BASE: %X, ADDR: %X\n", pci_base, pci_off);
			for(;;);
			pci_addr = pci_base + pci_off;
			asm("movb $0xb1, %ah");
			asm("movb $0x01, %al");
			asm("pushl %cs");
			//asm("call %0"::"m" (pci_addr));
			asm("call 0xfb200");
			kprintf("fpd: %i\n", -find_pci_device(0,0,0));
			kprintf("fpcc: %i\n", -find_pci_class_code(0,0));
			for(;;);
			//
			
			
			//asm("movw $16, %ax");
			//asm("movw %ax, %ds");
			//asm("movw %ax, %ss");
			//asm("popl	%esp");
			printsegaddr(19);
		}
		bios32_sd++;
	}
*/	


